package services

import (
	"context"
	"github.com/golang/protobuf/ptypes/wrappers"
	"math"

	context2 "kop/framework/context"
	"kop/framework/errors"
	"kop/modules/ring/configuration"
	"kop/pb"
	"kop/pb/service"
	"kop/util/rand"

	captainC "kop/modules/captain/client"
	itemC "kop/modules/item/client"
	moneyC "kop/modules/money/client"
	ringC "kop/modules/ring/client"
)

type RingService struct {
	context2.Context
}

func (s *RingService) LevelUp(ctx context.Context, req *wrappers.Int32Value) (*pb.APIRingReply, error) {

	var reply pb.APIRingReply
	var ID = req.Value

	var roleID = s.GetRoleID(ctx)

	var ring, err = ringC.GetRing(roleID, ID)
	if err != nil {
		return &reply, err
	}

	if ring.Level >= ring.MaxLevel {
		return &reply, errors.New("max level")
	}

	// del item
	if reply.Item, err = itemC.DelItem(roleID, s.GetServerID(ctx), ring.LevelUpItem.ItemID, ring.LevelUpItem.Number); err != nil {
		return &reply, err
	}

	ring.Level += 1
	ring.LevelUpDelItemNum += ring.LevelUpItem.Number
	ringC.Save(roleID, ring)

	// 修改船长属性
	go captainC.CaptainService.AsyncSaveRing(ctx, &service.CaptainEquipRequest{Ring: ring})

	reply.Ring = ring
	//reply.Captain = captain

	return &reply, nil
}

func (s *RingService) Refine(ctx context.Context, req *pb.APIRingRefineRequest) (*pb.APIRingReply, error) {

	var reply pb.APIRingReply

	if req.Option == 0 {
		// 1,2,3,4 4个选项中选一个
		return &reply, errors.ParamError
	}

	var roleID = s.GetRoleID(ctx)

	ring, err := ringC.GetRing(roleID, req.ID)
	if err != nil {
		return &reply, err
	}

	if ring.RefineItem.ItemID == 0 {
		return &reply, errors.New("can't refine")
	}

	if reply.Item, err = itemC.DelItem(roleID, s.GetServerID(ctx), ring.RefineItem.ItemID, ring.RefineItem.Number); err != nil {
		return &reply, err
	}

	//****************************** 固定概率 ******************************
	var element int32 = 0
	var r = rand.Int32(0, 99)
	if r < 5 {
		element = rand.Int32(0, 4) + 26
	} else if r < 15 {
		element = rand.Int32(0, 4) + 21
	} else if r < 35 {
		element = rand.Int32(0, 4) + 16
	} else if r < 65 {
		element = rand.Int32(0, 4) + 11
	} else {
		element = rand.Int32(0, 9) + 1
	}
	//****************************** 固定概率 ******************************

	switch req.Option {
	case 1:
		ring.Element1 = element
	case 2:
		ring.Element2 = element
	case 3:
		ring.Element3 = element
	case 4:
		ring.Element4 = element
	}

	ringC.Save(roleID, ring)

	// 修改船长属性
	go captainC.CaptainService.AsyncSaveRing(ctx, &service.CaptainEquipRequest{Ring: ring})

	reply.Ring = ring
	//reply.Captain = captain

	return &reply, nil
}

func (s *RingService) Make(ctx context.Context, req *pb.APIRingMakeRequest) (*pb.APIRingMakeReply, error) {

	var reply pb.APIRingMakeReply
	if req.Number < 1 || req.Number > 100 {
		return &reply, errors.ParamError
	}

	var roleID = s.GetRoleID(ctx)

	ringConf, err := configuration.GetByRingID(req.RingID)
	if err != nil {
		return &reply, err
	}

	var rings = ringC.GetByRingID(roleID, ringConf.NeedRingID)

	// 已装备的戒指ID
	var equipIDs = captainC.GetByInRingUniqueIDs(roleID)

	var delNumber = 3 * req.Number

	// 准备删除的戒指ID
	reply.IDs = make([]int32, 0, delNumber)

	for _, ring := range rings {

		if ring.Level > 0 || ring.Element1 > 0 || ring.Element2 > 0 || ring.Element3 > 0 || ring.Element4 > 0 {
			// 强化, 重铸过的不能用来合成
			continue
		}

		var find = false
		for _, ID := range equipIDs {
			if ID == ring.ID {
				find = true
			}
		}

		if find {
			// 已装备的不能用来合成
			continue
		}

		reply.IDs = append(reply.IDs, ring.ID)
		if len(reply.IDs) == int(delNumber) {
			break
		}
	}

	if len(reply.IDs) < int(delNumber) {
		return &reply, errors.New("材料戒指不够")
	}

	var needCoin = ringConf.NeedMoney * int64(req.Number)
	if reply.Money, err = moneyC.SubCoin(ctx, needCoin); err != nil {
		return &reply, err
	}

	if ringConf.NeedItemID > 0 {
		// del item
		if reply.Item, err = itemC.DelItem(roleID, s.GetServerID(ctx), ringConf.NeedItemID, req.Number); err != nil {
			return &reply, err
		}
	}

	reply.Rings, err = ringC.Make(roleID, req.RingID, reply.IDs)
	return &reply, err
}

const DecomposeItemID = 101030

// 分解戒指
func (s *RingService) Decompose(ctx context.Context, req *pb.Int32Slice) (*pb.APIRingDecomposeReply, error) {

	var reply = pb.APIRingDecomposeReply{
		DelIDs: []int32{},
	}

	if len(req.Slices) == 0 {
		return &reply, errors.ParamError
	}

	var roleID = s.GetRoleID(ctx)

	// 已装备的戒指ID
	var equipIDs = captainC.GetByInRingUniqueIDs(roleID)
	for _, ID := range req.Slices {
		for _, equipID := range equipIDs {
			if ID == equipID {
				return &reply, errors.New("已装备的不能分解")
			}
		}
	}

	var itemNumber int32 = 0

	var rings = ringC.GetRings(roleID)

	for _, ID := range req.Slices {

		var find = false
		for _, ring := range rings {
			if ID == ring.ID {

				if ring.Level > 1 {
					return &reply, errors.New("强化过的不能分解")
				}

				ringConf, err := configuration.GetByRingID(ring.RingID)
				if err != nil {
					return &reply, err
				}
				itemNumber += ringConf.DecomposeCount

				find = true
			}
		}

		if !find {
			return &reply, errors.ParamError
		}
	}

	ringC.Delete(req)

	for _, ID := range req.Slices {
		reply.DelIDs = append(reply.DelIDs, ID)
	}

	reply.Item = itemC.AddItem(roleID, DecomposeItemID, itemNumber)
	reply.RawItem = &pb.RawItem{ItemID: DecomposeItemID, Number: itemNumber}
	return &reply, nil
}

// 重置
func (s *RingService) Reset(ctx context.Context, req *pb.Int32Slice) (*pb.APIRingResetReply, error) {

	var reply = pb.APIRingResetReply{
		Rings:    []*pb.Ring{},
		Items:    []*pb.Item{},
		RawItems: []*pb.RawItem{},
	}

	if len(req.Slices) == 0 {
		return &reply, errors.ParamError
	}

	var roleID = s.GetRoleID(ctx)

	var equipIDs = captainC.GetByInRingUniqueIDs(roleID)
	for _, ID := range req.Slices {
		for _, equipID := range equipIDs {
			if ID == equipID {
				return &reply, errors.New("已装备的不能重置")
			}
		}
	}

	var itemMap = make(map[int32]int32)

	for _, ID := range req.Slices {

		ring, err := ringC.GetRing(roleID, ID)
		if err != nil {
			return &reply, err
		}

		if ring.Level < 1 {
			return &reply, errors.New("强化0不需要重置")
		}

		if _, ok := itemMap[ring.LevelUpItem.ItemID]; !ok {
			itemMap[ring.LevelUpItem.ItemID] = 0
		}
		itemMap[ring.LevelUpItem.ItemID] += int32(math.Max(float64(ring.LevelUpDelItemNum), 1))

		ring.Level = 0
		ring.Element1 = 0
		ring.Element2 = 0
		ring.Element3 = 0
		ring.Element4 = 0
		ring.LevelUpDelItemNum = 0

		ringC.Save(roleID, ring)
		reply.Rings = append(reply.Rings, ring)
	}

	for itemID, number := range itemMap {

		reply.Items = append(reply.Items, itemC.AddItem(roleID, itemID, number))
		reply.RawItems = append(reply.RawItems, &pb.RawItem{ItemID: itemID, Number: number})
	}
	return &reply, nil
}

func (s *RingService) AddRing(ctx context.Context, req *wrappers.Int32Value) (*pb.Ring, error) {

	var roleID = s.GetRoleID(ctx)
	return ringC.Create(roleID, req.Value), nil
}
